﻿using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace PefStudio.Windows
{
    class ExtensionsService
    {
        internal static void CreateMenu(ContextMenuStrip contextMenuStrip, IEnumerable<IMenuItem> items, Form parentForm)
        {
            CreateMenu(contextMenuStrip.Items, items, parentForm);
            contextMenuStrip.Opening += ContextMenuStrip_Opening;
        }

        internal static void CreateMenu(ToolStripItemCollection toolStripItemCollection, IEnumerable<IMenuItem> items, Form parentForm)
        {
            var sortedExtensionItems = Sort(items);
            foreach (var extensionItem in sortedExtensionItems)
            {
                if (extensionItem.HasSeparator == true && toolStripItemCollection.Count > 0)
                {
                    var separator = new ToolStripSeparator();
                    toolStripItemCollection.Add(separator);
                    extensionItem.ToolStripSeparator = separator;
                }
                extensionItem.ParentForm = parentForm;

                var toolStripItem = extensionItem as ToolStripItem;
                if (toolStripItem != null) toolStripItemCollection.Add(toolStripItem);
            }
        }

        public static void ContextMenuStrip_Opening(object sender, System.ComponentModel.CancelEventArgs e)
        {
            var contextMenuStrip = sender as ContextMenuStrip;
            if (contextMenuStrip == null) return;

            foreach (var item in contextMenuStrip.Items)
            {
                if (item is IMenuItem)
                {
                    var menuItem = item as IMenuItem;
                    menuItem.ConditionEvaluate();
                }
            }
        }

        public static void CreateStatusBar(ToolStripItemCollection toolStripItemCollection, IEnumerable<IStatusBarItem> items)
        {
            var sortedExtensionItems = Sort(items);
            foreach (var extensionItem in sortedExtensionItems)
            {
                if (extensionItem.HasSeparator == true && toolStripItemCollection.Count > 1)
                    toolStripItemCollection.Add(new ToolStripSeparator());

                var toolStripItem = extensionItem as ToolStripItem;
                if (toolStripItem != null) toolStripItemCollection.Add(toolStripItem);
            }
        }

        public static void CreateToolStrip(ToolStripItemCollection toolStripItemCollection, IEnumerable<IToolStripItem> items)
        {
            var sortedExtensionItems = Sort(items);
            foreach (var extensionItem in sortedExtensionItems)
            {
                if (extensionItem.HasSeparator == true && toolStripItemCollection.Count > 1)
                    toolStripItemCollection.Add(new ToolStripSeparator());

                var toolStripItem = extensionItem as ToolStripItem;
                if (toolStripItem != null) toolStripItemCollection.Add(toolStripItem);
            }
        }

        public static IList<T> Sort<T>(IEnumerable<T> items) where T : IExtension
        {
            var extensionItems = new List<T>(items.OrderByDescending(c => c.Index));
            var sortedExtensionItems = new List<T>();
            var unsortedExtensionItems = new List<T>();
            foreach (T extensionItem in extensionItems)
            {
                if (extensionItem.InsertRelativeToID == null)
                {
                    sortedExtensionItems.Add(extensionItem);
                }
                else if (FindByID(extensionItem.InsertRelativeToID, extensionItems) == -1)
                {
                    sortedExtensionItems.Add(extensionItem);
                }
                else
                {
                    unsortedExtensionItems.Add(extensionItem);
                }
            }
            while (unsortedExtensionItems.Count > 0)
            {
                var stillUnsortedExtensionItems = new List<T>();
                int startingCount = unsortedExtensionItems.Count;
                foreach (T extensionItem in unsortedExtensionItems)
                {
                    int index = FindByID(extensionItem.InsertRelativeToID, sortedExtensionItems);
                    if (index > -1)
                    {
                        if (extensionItem.BeforeRelativeID == true)
                        {
                            sortedExtensionItems.Insert(index, extensionItem);
                        }
                        else
                        {
                            if (index == sortedExtensionItems.Count - 1)
                            {
                                //it's to be inserted after the last item in the list
                                sortedExtensionItems.Add(extensionItem);
                            }
                            else
                            {
                                sortedExtensionItems.Insert(index + 1, extensionItem);
                            }
                        }
                    }
                    else
                    {
                        stillUnsortedExtensionItems.Add(extensionItem);
                    }
                }

                if (startingCount == stillUnsortedExtensionItems.Count)
                {
                    // Pick one and add it at the end.
                    sortedExtensionItems.Add(stillUnsortedExtensionItems[0]);
                    stillUnsortedExtensionItems.RemoveAt(0);
                }
                unsortedExtensionItems = stillUnsortedExtensionItems;
            }

            return sortedExtensionItems;
        }

        private static int FindByID<T>(string id, IList<T> extensions) where T : IExtension
        {
            for (int i = 0; i < extensions.Count; i++)
            {
                if (extensions[i].ID == id)
                {
                    return i;
                }
            }
            return -1;
        }
    }
}
